package cn.birdbaby.plugins.annotator.classannotator.gen.genannotator;

import cn.birdbaby.plugins.annotator.AbstractAnnotator;
import cn.birdbaby.plugins.annotator.AnnotatorRegistry;
import cn.birdbaby.plugins.annotator.Context;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @author llorando 7/8/24 1:41 pm
 */
public class AnnotatorProcessor {

    protected Context context;

    private List<String> tasks;

    private String groupId;

    public AnnotatorProcessor(PsiElement psiElement, String groupId, List<String> tasks) {
        this.context = new Context(psiElement);
        this.tasks = tasks;
        this.groupId = groupId;
    }

    //添加一个执行器，和执行任务的概念，执行任务中规定每次需要生成的注解种类
    //模版方法没办法对子类进行批次处理
    public final void addGenAnnotation() {

        List<PsiAnnotation> genAnnotation = buildPsiAnnotation();
        importFix();
//        PsiJavaCodeReferenceElement constants = JavaPsiFacade.getElementFactory(project)
//                .createReferenceFromText(packageName + ".Constants", psiClass);
//
//        ImportClassFix constantsFix = new ImportClassFix(constants);
//        constantsFix.invoke(project, editor, psiJavaFile);
        importClassIfNotImported(context.getProject(), context.getParentPackageName() + ".infrastruction.constant.Constants");
    }

    public void importFix() {
//        for(PsiAnnotation annotation:genAnnotation){
//            PsiJavaCodeReferenceElement refElement = annotation.getNameReferenceElement();
//            ImportClassFix annotationFix = new ImportClassFix(refElement);
//            annotationFix.invoke(context.getProject(), context.getEditor(), context.getPsiJavaFile());
//        }

        // 执行写操作来添加缺失的导入
        Collection<PsiJavaCodeReferenceElement> references = PsiTreeUtil.findChildrenOfAnyType(context.getPsiJavaFile(), PsiJavaCodeReferenceElement.class);

        PsiImportList importList = (context.getPsiJavaFile()).getImportList();
        for (PsiReference reference : references) {
            PsiJavaCodeReferenceElement refElement = (PsiJavaCodeReferenceElement) reference;
            if (refElement.resolve() == null) {
                String qName = refElement.getQualifiedName();
                AbstractAnnotator annotator = (AbstractAnnotator) AnnotatorRegistry.find(qName);
                if (annotator != null) {
                    String fullQName = annotator.getFullName();
                    PsiClass aClass = JavaPsiFacade.getInstance(context.getProject()).findClass(fullQName, GlobalSearchScope.allScope(context.getProject()));
                    PsiImportStatementBase importStatement = JavaPsiFacade.getElementFactory(context.getProject()).createImportStatement(aClass);
                    importList.add(importStatement);

                }
            }
        }
    }


    //通过当前任务上下文，获取这些参数
    public List<PsiAnnotation> buildPsiAnnotation() {
        List<PsiAnnotation> psiAnnotations = new ArrayList<>();
        for (String task : tasks) {
            AutoGenAnnotator annotator = (AutoGenAnnotator) AnnotatorRegistry.find(task);
            PsiAnnotation tmp = context.getPsiModifierList().addAnnotation(annotator.getSimpleName());
            // Set the pkgName attribute
            PsiAnnotationMemberValue pkgNameValue = JavaPsiFacade.getElementFactory(context.getProject()).createExpressionFromText("\"" + annotator.getPkgName(context) + "\"", context.getPsiClass());
            tmp.setDeclaredAttributeValue("pkgName", pkgNameValue);

            //只有包含sourcePath属性的Gen注解会跑进来
            if (annotator.hasSourcePath()) {
                //找了一天的api，谁想到直接引用就行
                PsiAnnotationMemberValue sourcePathValue = JavaPsiFacade.getElementFactory(context.getProject()).createExpressionFromText("Constants.GEN_API_SOURCE", context.getPsiClass());
                tmp.setDeclaredAttributeValue("sourcePath", sourcePathValue);
            }

            if (annotator.hasMapperPath()) {
                PsiAnnotationMemberValue mapperPath = JavaPsiFacade.getElementFactory(context.getProject()).createExpressionFromText("Constants.CUSTOMER_MAPPER_PKG", context.getPsiClass());
                tmp.setDeclaredAttributeValue("customerMapperPkgName", mapperPath);
            }
            psiAnnotations.add(tmp);
        }
        return psiAnnotations;
    }

    public void importClassIfNotImported(final Project project, final String className) {
        WriteCommandAction.runWriteCommandAction(project, (Computable<Object>) () -> {
            PsiImportList importList = context.getPsiJavaFile().getImportList();
            if (importList != null) {
                // Check if the class is already imported
                PsiClass aClass = JavaPsiFacade.getInstance(project).findClass(className, GlobalSearchScope.moduleScope(ModuleUtil.findModuleForFile(context.getPsiJavaFile())));
                if (aClass != null) {
                    if (!isAlreadyImported(importList, aClass)) {
                        try {
                            PsiImportStatementBase importStatement = JavaPsiFacade.getElementFactory(project).createImportStatement(aClass);
                            importList.add(importStatement);
                        } catch (IncorrectOperationException e) {
                            // Handle exception
                            e.printStackTrace();
                        }
                    }
                } else {
                    // Class not found, handle this case as needed.
                    System.out.println("Class not found: " + className);
                }
            }
            return true;
        });
    }

    private static boolean isAlreadyImported(PsiImportList importList, PsiClass aClass) {
        PsiImportStatementBase[] existingImports = importList.getAllImportStatements();
        String qualifiedName = aClass.getQualifiedName();
        for (PsiImportStatementBase importStatement : existingImports) {
            PsiJavaCodeReferenceElement importReference = importStatement.getImportReference();
            if (importReference != null && importReference.getCanonicalText().equals(qualifiedName)) {
                return true;
            }
        }
        return false;
    }

}
